5.08. Философия языка
Философия языка
Что такое объект - мы помним. Мы рассматривали его с точки зрения современных концепций, как Java, но всё же принцип «всё есть объект» понять несложно. Даже самые базовые сущности в Smalltalk являются обхектами.
К примеру, 1234 будет объектом класса Integer, у которого есть метод factorial.
true и false - объекты, отвечающие на сообщения ifTrue, ifFalse.
nil (аналог null) тоже объект, единственный экземпляр класса UndefinedObject (неопределенный объект).
Классы - объекты, экземпляры метаклассов. Методы - объекты. Блоки кода - объекты, которые тоже можно передавать, хранить, вызывать. То есть, в системе нет «второсортных сущностей», и всё подчиняется единой модели.
Почему мы так акцентируем на этом? Понятнее станет, если рассмотреть другие языки.
В Java, например, не всё объект, допустим int и boolean - это примитивы. В C#, int - это структура, но не объект в полном смысле. В Python есть определенные «оптимизации», а в JavaScript примитивы не всегда ведут себя как объекты при доступе к методам. Словом, везде есть «но». Smalltalk же доводит идею до абсолюта: нет никакого разделения между данными и поведением, между типами и объектами.
Единственный способ взаимодействия - это посылка сообщений. Мы как-то изучали уже термин «вызов» функции или метода. То есть мы говорим «объект.метод()». В Smalltalk немного иначе - здесь мы посылаем сообщение в объект. Тут есть фундаментальная разница в модели вычислений - сообщение не привязано к классу, оно отправляется объекту, т.е. оно независимое. А объект же сам решает, как ответить. Если объект не понимает сообщение — он получает doesNotUnderstand:, и может динамически среагировать (например, делегировать, создать метод на лету, выбросить ошибку).
Пример - условие без операторов:
(x > 0) ifTrue: [ 'positive' ] ifFalse: [ 'negative' ]
Что здесь происходит?
- (x > 0) возвращает true или false — объект.
- Мы посылаем ему сообщение ifTrue:ifFalse:.
- true и false реализуют это сообщение по-разному.
Как видим, какого-то ветвления в синтаксисе нет, есть лишь поведение объектов.
В Smalltalk нет аннотаций типов. Никаких String name, List<int>. Тип является свойством объекта, а не переменной:
| x |
x := 42.
x := 'hello'.
x := [ 1 + 2 ].
Но ошибки обнаруживаются только во время выполнения, и сложно порой понять, что ожидает метод, и как следствие - труднее оптимизировать. В других языках мы пишем код в редакторе, сохраняем в файл, запускаем компилятор, запускаем программу, при ошибках читаем логи, исправляем, перезапускаем.
В ST же мы погружаемся в работающую систему, где код - это объекты в памяти, и изменяя класс, мы немедленно меняем поведение ситемы. Словом, отладчик не является внешним инструментов, а своего рода «окно» в текущее состояние выполнения. Это как если бы вы могли изменить скрипт на веб-странице прямо в браузере — и изменения вступили в силу мгновенно, без перезагрузки.
А IDE в Smalltalk — не программа для написания кода. Это сама программа.
Необычно, правда?
Smalltalk — один из первых языков с полной рефлексией:
- Любой объект может сказать: «Кто мой класс?» (obj class)
- Любой класс может вернуть список своих методов (MyClass methods)
- Можно добавить метод в класс на лету:
String compile: 'reverseUppercase ^ self reversed asUppercase'
- Можно перехватить неизвестные сообщения:
doesNotUnderstand: aMessage
^ 'I don''t know ', aMessage selector
Многие практики современного программирования родились в этой экосистеме.
К примеру, рефакторинг - этот термин популяризирован Кентом Беком, который работал на Smalltalk. А также юнит-тестирование (SUnit), первый фреймворк для модульного тестирования, создан в Smalltalk (прообраз JUnit, NUnit). И конечно же экстремальное программирование, Extreme Programming (XP) — Кент Бек разработал его, используя Smalltalk и SUnit.
А теперь о минусах.
Как можно понять, есть обратная сторона, связанная с теми же особенностями. Например, проблемы безопасности. Полная рефлексия и возможность модификации системы на лету — риск, ведь любой код может изменить любой класс, а вредоносный скрипт может переписать что угодно. Это делает Smalltalk непригодным для систем с высокими требованиями к безопасности. Собственно современные языки в первую очередь потому и «живы» - из-за своей безопасности.
Далее - производительность. Интерпретируемый байт-код, паузы при автоматической сборке мусора, большое количество объектов - на практике всё это не подходит для высоконагруженных систем.
И конечно, дизайн. Отсутствие жёсткой структуры приводит к хаосу, и легко создавать магию (внезапно появляющиеся методы, перехват сообщений), и без дисциплины вся система станет непредсказуемой. Через неделю даже сам программист может не разобраться в своём же коде. Всё это не делает язык идеальным. Скорее полезным с точки зрения идеи и философии, учить думать иначе.
Можно встретить такие выражения, как «пуристская теория», которая как раз и подразумевает модель мышления, в которой программированием является не управлеине процессором, а организация диалога между объектами. Вы не пишете инструкции — вы создаёте среду, в которой объекты общаются. Вы не вызываете функции — вы посылаете сообщения.
И суть в том, что мир состоит из изолированных сущностей (объектов), между которыми есть один единственный способ взаимодействия - посылка сообщений. И поведение делегируется, объект сам решает, как ответить. В реальной жизни всё так же - вы не управляете человеком, вы просите его что-то сделать, он может сказать «да», «нет», проигнорировать или ответить как-то ещё, вы не лезете внутрь его головы и не переписываете его мышление. Это и есть чистое ООП. И сообщение не будет гарантировать, что объект его поймёт, выполнит его так, как вы ожидаете, и он вообще ответит. Можно встретить забавный пример, если написать:
bird fly
Если bird - это Sparrow (попугай), то полетит. Если Penguin (пингвин), он получит сообщение, но ответит иначе:
fly
self inform: 'I can''t fly!'
Если bird — это Rock, он получит doesNotUnderstand: #fly — и можно перехватить.
Смысл уловили? Сообщение — это предложение.
В итоге у нас нет жёсткой связи между отправителем и получателем, и вы не знаете как ответит объект, что делает его изолированным субъектом со своим внутренним состоянием, реакцией.
Такие дела. Поэтому не ругайтесь с пуристами и не убеждайте, что какой-то язык настоящее ООП, кроме ST.